package jadeCW.behaviour;

import jade.core.behaviours.Behaviour;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jadeCW.PatientAgent;
import jadeCW.output.Printer;

import java.util.List;


/**
 * Request Appointment behaviour class
 * 
 * @author br08, dac108, dv08
 */
public class RequestAppointment extends Behaviour {
	/**
	 * Type identifier for message
	 */
	public static final String TYPE = "request-appointment";
	
	/**
	 * Generated serialisation ID
	 */
	private static final long serialVersionUID = 3871087347463768127L;

	private int step = 0;
	private MessageTemplate template;

	@Override
	public void action() {
		// must be run on a patient
		if (!(myAgent instanceof PatientAgent)) {
			return;
		}

		PatientAgent patient = (PatientAgent) myAgent;

		switch (this.step) {
		case 0:
			List<DFAgentDescription> hospitals = patient
					.getAppointmentAllocators();

			// if no known hospitals, done
			if (hospitals.size() == 0) {
				this.step = 2;
				return;
			}

			// set up request
			ACLMessage request = new ACLMessage(ACLMessage.REQUEST);

			// send to all hospitals
			for (DFAgentDescription hospital : hospitals) {
				request.addReceiver(hospital.getName());
			}

			// set message type
			request.setConversationId(TYPE);
			request.setReplyWith(TYPE + System.currentTimeMillis());

			// prepare the template to get responses
			this.template = MessageTemplate.and(MessageTemplate
					.MatchConversationId(TYPE),
					MessageTemplate.MatchInReplyTo(request.getReplyWith()));

			Printer.printRequestSend(patient);
			
			// send request
			patient.send(request);

			step = 1;
			break;
		case 1:
			// receive request
			ACLMessage reply = patient.receive(this.template);

			if (reply != null) {
				switch (reply.getPerformative()) {
				// if the response is an offer
				case ACLMessage.PROPOSE:
					int appointment = Integer.parseInt(reply.getContent());

					// update the parent with the appointment
					patient.setAppointment(appointment);
					
					Printer.printRequestReceiveAccept(patient, appointment);
					
					break;
				// if the response is a refusal
				case ACLMessage.REFUSE:
					// do nothing
					Printer.printRequestReceiveRefuse(patient);
					
					break;
				}
				
				this.step = 2;
			} else {
				block();
			}
		}
	}

	@Override
	public boolean done() {
		return (this.step == 2);
	}
}
